<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>Tutorial Demo</title>
  <style>
    #container{
      width: 500px;
      height: 800px;
    }
  </style>
</head>
<body>
/* 图的画布容器 */
<div id="container"></div>
/* 引入 G6 */
<script src="https://gw.alipayobjects.com/os/lib/antv/g6/4.3.11/dist/g6.min.js"></script>
<script>

  const nodeData = [{
    name: '块1-1', // 节点名
    linkTargetName: '节点B', // 连线目标节点
    linkValue: ' ', // 连线介绍
    coordConfig: {
      level: '0-error',
      effect: {
        show: true,
        smooth: false,
        trailLength: 0,
        symbol: 'circle',
        color: '#fb3f3f',
        symbolSize: 10,
        period: 3,
        delay: 1500,
        loop: true
      },
      lineStyle: {
        normal: {
          curveness: 0,
          color: '#fb3f3f',
          width: 1.4
        }
      }
    }, // 连线动态箭头配置，没有就不需要此配置
    value: [10, 190],
    draggable: false,
    fixed: true,
    symbol: 'circle',
    symbolSize: 40,
    itemStyle: {
      color: '#fb3f3f'
    }
  },
    {
      name: '块1-2',
      linkTargetName: '节点B',
      linkValue: ' ',
      coordConfig: {
        level: '0'
      },
      value: [10, 150],
      draggable: false,
      fixed: true,
      symbol: 'circle',
      symbolSize: 40
    }, {
      name: '块2',
      linkTargetName: '节点C',
      linkValue: ' ',
      coordConfig: {
        level: '0'
      },
      value: [10, 100],
      draggable: false,
      fixed: true,
      symbol: 'circle',
      symbolSize: 40
    }, {
      name: '块3',
      linkTargetName: '节点D',
      linkValue: ' ',
      coordConfig: {
        level: '0'
      },
      value: [10, 40],
      draggable: false,
      symbol: 'circle',
      symbolSize: 40
    },
    // 节点B,C,D ....n
    {
      name: '节点B',
      linkTargetName: '应用端',
      linkValue: ' ',
      coordConfig: {
        level: '1'
      },
      symbol: 'circle',
      symbolSize: 50,
      draggable: false,
      value: [220, 160]
    }, {
      name: '节点C',
      linkTargetName: '应用端',
      linkValue: ' ',
      coordConfig: {
        level: '1'
      },
      symbol: 'circle',
      symbolSize: 60,
      draggable: false,
      value: [220, 100]
    }, {
      name: '节点D',
      linkTargetName: '应用端',
      linkValue: ' ',
      coordConfig: {
        level: '1'
      },
      symbol: 'circle',
      symbolSize: 60,
      draggable: false,
      value: [220, 40]
    }, {
      name: '应用端',
      linkTargetName: '应用端',
      linkValue: ' ',
      // coordConfig: {level: 2},
      symbolSize: 60,
      symbol: 'circle',
      draggable: false,
      value: [400, 100]
    }
  ]
  window.onload = function (){
    const container = document.getElementById('container')
    const width = container.scrollWidth
    const height = container.scrollHeight || 500
    // let legendDiv = document.createElement('div')
    // 自定义tooltip
    const tooltip = new G6.Tooltip({
      // offsetX and offsetY include the padding of the parent container
      // offsetX 与 offsetY 需要加上父容器的 padding
      offsetX: 10,
      offsetY: 10,
      // the types of items that allow the tooltip show up
      // 允许出现 tooltip 的 item 类型
      itemTypes: ['node', 'edge'],
      // custom the tooltip's content
      // 自定义 tooltip 内容
      getContent: (e) => {
        // console.log('e', e)
        const outDiv = document.createElement('div')
        outDiv.style.width = 'fit-content'
        outDiv.style.height = 'fit-content'
        outDiv.style.textAlign = 'justify'
        const model = e.item.getModel()
        // console.log('model', model)
        if (e.item.getType() === 'node') {
          outDiv.innerHTML = `记录数：${model.logNumber}</br> 耗时：${model.costTime}</br> 系统: ${model.systemName}</br> 服务: ${model.serviceName}`
        } else {
          // console.log('model', model)
          // outDiv.style.display = 'none'
          outDiv.innerHTML = `原点：${model.source}, \n 终点：${model.target}`
        }
        return outDiv
      }
    })
    // Background Animation 背景特效
    G6.registerNode('background-animate', {
      afterDraw (cfg, group) {
        let r = cfg.size / 2
        if (isNaN(r)) {
          r = cfg.size[0] / 2
        }
        // 第一个背景圆
        const back1 = group.addShape('circle', {
          zIndex: -3,
          attrs: {
            x: 0,
            y: 0,
            r,
            fill: cfg.color,
            opacity: 0.6
          },
          // must be assigned in G6 3.3 and later versions. it can be any value you want
          name: 'circle-shape1'
        })
        // 第二个背景圆
        const back2 = group.addShape('circle', {
          zIndex: -2,
          attrs: {
            x: 0,
            y: 0,
            r,
            fill: '#4592FF', // 为了显示清晰，随意设置了颜色
            opacity: 0.6
          },
          // must be assigned in G6 3.3 and later versions. it can be any value you want
          name: 'circle-shape2'
        })
        // 第三个背景圆
        const back3 = group.addShape('circle', {
          zIndex: -1,
          attrs: {
            x: 0,
            y: 0,
            r,
            fill: '#52D5CC',
            opacity: 0.6
          },
          // must be assigned in G6 3.3 and later versions. it can be any value you want
          name: 'circle-shape3'
        })
        group.sort() // 排序，根据 zIndex 排序

        // 第一个背景圆逐渐放大，并消失
        back1.animate({
          r: r + 10,
          opacity: 0.1
        }, {
          repeat: true, // 循环
          duration: 3000,
          easing: 'easeCubic',
          delay: 0 // 无延迟
        })

        // 第二个背景圆逐渐放大，并消失
        back2.animate({
          r: r + 10,
          opacity: 0.1
        }, {
          repeat: true, // 循环
          duration: 3000,
          easing: 'easeCubic',
          delay: 1000 // 1 秒延迟
        }) // 1 秒延迟

        // 第三个背景圆逐渐放大，并消失
        back3.animate({
          r: r + 10,
          opacity: 0.1
        }, {
          repeat: true, // 循环
          duration: 3000,
          easing: 'easeCubic',
          delay: 2000 // 2 秒延迟
        })
      }
    }, 'circle')
    // 边的动画特效
    G6.registerEdge('circle-running', {
        afterDraw (cfg, group) {
          // get the first shape in the group, it is the edge's path here=
          // console.log('group', group)
          const shape = group.get('children')[0]
          // the start position of the edge's path
          const startPoint = shape.getPoint(0)

          // add red circle shape
          const circle = group.addShape('circle', {
            attrs: {
              x: startPoint.x,
              y: startPoint.y,
              fill: 'rgba(82,213,204,0.54)',
              r: 3
            },
            name: 'circle-shape'
          })

          // animation for the red circle
          circle.animate(
            (ratio) => {
              // the operations in each frame. Ratio ranges from 0 to 1 indicating the prograss of the animation. Returns the modified configurations
              // get the position on the edge according to the ratio
              const tmpPoint = shape.getPoint(ratio)
              // returns the modified configurations here, x and y here
              return {
                x: tmpPoint.x,
                y: tmpPoint.y
              }
            },
            {
              repeat: true, // Whether executes the animation repeatly
              duration: 3000 // the duration for executing once
            }
          )
        }
      },
      'cubic' // extend the built-in edge 'cubic'
    )
    const lineDash = [4, 2, 1, 2]
    // 线的特效
    G6.registerEdge('line-dash', {
        afterDraw (cfg, group) {
          // get the first shape in the group, it is the edge's path here=
          const shape = group.get('children')[0]
          let index = 0
          // Define the animation
          shape.animate(
            () => {
              index++
              if (index > 9) {
                index = 0
              }
              const res = {
                lineDash,
                lineDashOffset: -index
              }
              // returns the modified configurations here, lineDash and lineDashOffset here
              return res
            },
            {
              repeat: true, // whether executes the animation repeatly
              duration: 3000 // the duration for executing once
            }
          )
        }
      },
      'cubic' // extend the built-in edge 'cubic'
    )
    const graph = new G6.TreeGraph({
      container: 'container',
      width,
      height,
      plugins: [tooltip],
      modes: {
        default: [
          {
            type: 'collapse-expand',
            onChange: function onChange (item, collapsed) {
              const data = item.get('model').data
              data.collapsed = true
              return true
            }
          },
          'drag-canvas',
          'zoom-canvas'
        ]
      },
      defaultEdge: {
        type: 'circle-running',
        size: 1,
        style: {
          radius: 0,
          offset: 10,
          endArrow: true,
          lineWidth: 0.5,
          /* and other styles */
          stroke: '#B2B2B2'
        }
      },
      layout: {
        type: 'mindmap',
        direction: 'H',
        getHeight: () => {
          return 60
        },
        getWidth: () => {
          return 50
        },
        getVGap: () => {
          return 30
        },
        getHGap: () => {
          return 80
        }
      }
    })

    // 结点位置
    let centerX = 0
    graph.node(function (node) {
      if (node.id === 'Z') {
        centerX = node.x
      }

      // 记录数、节点耗时、系统名称、服务名称
      return {
        // label: `${fittingString(node.label, 140, 12)}`,
        label: `${node.label}`,
        labelCfg: {
          fontSize: 14,
          position:
            node.children && node.children.length > 0
              ? node.id === 'Z' ? 'left' : 'bottom'
              : node.x > centerX
              ? 'right'
              : 'left',
          offset: 10
        }
      }
    })
    graph.data(nodeData[0])
    graph.render()
    graph.fitView()
    if (typeof window !== 'undefined') {
      window.onresize = () => {
        if (!graph || graph.get('destroyed')) return
        if (!container || !container.scrollWidth || !container.scrollHeight) return
        graph.changeSize(container.scrollWidth, container.scrollHeight)
      }
    }
  }



 /* const lineDash = [4, 2, 1, 2];
  window.onload = function () {
    G6.registerEdge(
      'circle-running',
      {
        afterDraw(cfg, group) {
          // get the first shape in the group, it is the edge's path here=
          const shape = group.get('children')[0];
          // the start position of the edge's path
          const startPoint = shape.getPoint(0);
          let index = 0;
          // add red circle shape
          const circle = group.addShape('circle', {
            attrs: {
              x: startPoint.x,
              y: startPoint.y,
              fill: '#1890ff',
              lineWidth: 10,
            },
            name: 'line-shape',
          });
          circle.animate(
            () => {
              index++;
              if (index > 9) {
                index = 0;
              }
              const res = {
                lineDash,
                lineDashOffset: -index,
              };
              // returns the modified configurations here, lineDash and lineDashOffset here
              return res;
            },
            {
              repeat: true, // whether executes the animation repeatly
              duration: 3000, // the duration for executing once
            },
          );

        },
      },
      'cubic', // extend the built-in edge 'cubic'
    );

    const data = {
      nodes: [
        {
          id: 'node1',
          x: 100,
          y: 100,
          label: 'Node 1',
          labelCfg: {
            position: 'top',
          },
        },
        {
          id: 'node2',
          x: 300,
          y: 200,
          color: '#40a9ff',
          label: 'Node 2',
          labelCfg: {
            position: 'left',
            offset: 10,
          },
        },
      ],
      edges: [
        {
          source: 'node1',
          target: 'node2',
        },
      ],
    };

    const container = document.getElementById('container');
    const width = container.scrollWidth;
    const height = container.scrollHeight || 500;
    const graph = new G6.Graph({
      container: 'container',
      width,
      height,
      defaultEdge: {
        type: 'circle-running',
        style: {
          lineWidth: 12,
          stroke: '#bae7ff',
        },
      },
    });
    graph.data(data)
    graph.render()

  }
*/

  // 定义数据源
  /*import G6 from "@antv/g6";*/

  /*const data = {
    // 点集
    nodes: [
      {
        id: 'node1',
        x: 100,
        y: 200,
      },
      {
        id: 'node2',
        x: 300,
        y: 200,
      },
    ],
    // 边集
    edges: [
      // 表示一条从 node1 节点连接到 node2 节点的边
      {
        source: 'node1',
        target: 'node2',
      },
    ],
  };

  // 创建 G6 图实例
  const graph = new G6.Graph({
    container: 'mountNode', // 指定图画布的容器 id，与第 9 行的容器对应
    // 画布宽高
    width: 800,
    height: 500,
    defaultEdge: {
      type:  'def-cubic', // 扩展了内置边, 有边的事件
      style: {
        radius:          5,
        lineWidth:10,
        offset:          15,
        stroke:          '#ff0000',
        lineAppendWidth: 10, // 防止线太细没法点中
        endArrow:        true,
        shadowColor:"#ccc",
      },
    },
  });
  // 读取数据
  graph.data(data);
  // 渲染图
  graph.render();

  registerEdge();

  function registerEdge() {
    G6.registerEdge('def-cubic', {
      running: false,
      runAnimate(group) {
        let index = 0
        // 获得当前边的第1个图形，这里是边本身的 path
        const path = group.get('children')[0]
        const dashLine = group.addShape('path', {
          attrs: {
            offset: path.attrs.offset,
            path: path.attrs.path,
            stroke: '#1890ff',
            startArrow: path.attrs.startArrow,
            endArrow: path.attrs.endArrow
          },
          name: 'edge-dash'
        })

        dashLine.animate(
          radio => {
            index++
            return {
              lineDash: [2, 1, 2, 4],
              lineDashOffset: -index
            }
          },
          {
            repeat: true,
            duration: 3000
          },
        )
      },
      setState(name, value, item) {
        const group = item.getContainer()
        this.runAnimate(group)
      }
    })
  }*/
</script>
</body>
</html>
